package com.xiaoma.h5testdemo.common.widget

import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.webkit.*
import androidx.core.content.ContextCompat
import com.xiaoma.h5testdemo.R
import com.xiaoma.lib.log.KLog

/**
 * author: liangjingbo
 * date: 2023/8/10
 * describe:
 */
class XmProxyChromeWebView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : WebView(context, attrs) {

    var TAG = this.javaClass.simpleName + "_XMTag"

    var mWebViewChromeClientProxy: WebViewChromeClientProxy? = null
    var mWebViewClientProxy: WebViewClientProxy? = null
    private val mDefaultBit = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)

    init {
        initWebViewSetting(this)
        initWebViewClient(this)
        initWebChromeClient(this)
        setBackgroundColor(ContextCompat.getColor(context, R.color.color_window_bg))
    }

    fun setUserAgent(userAgent: String) {
        KLog.i(TAG, "setUserAgent() userAgent:$userAgent")
        // 设置WebView的User-Agent字符串。可以通过此方法自定义User-Agent字符串。
        this.settings.userAgentString = userAgent
    }

    private fun initWebViewSetting(webView: WebView) {
        val webSetting = webView.settings
        webSetting.javaScriptEnabled = true
        // 设置WebView是否支持多窗口，默认为false。
        webSetting.setSupportZoom(true)
        // 设置WebView是否支持多窗口，默认为false。
        webSetting.databaseEnabled = true
        // 设置是否允许WebView访问本地文件。如果设置为true，WebView将允许访问本地文件。
        webSetting.allowFileAccess = false
        // 设置 WebView 是否启用 DOM 存储(DOM Storage) 的功能
        webSetting.domStorageEnabled = true
        // 设置是否允许WebView访问其他资源。如果设置为true，WebView可以通过content协议访问其他资源。
        webSetting.allowContentAccess = false
        // 设置是否允许WebView访问来自"file"协议的任意URL。如果设置为true，WebView可以通过"file"协议访问任意URL
        webSetting.setAllowUniversalAccessFromFileURLs(false)
        //  设置是否允许WebView访问来自"file"协议的本地文件。如果设置为true，WebView可以通过"file"协议访问本地文件
        webSetting.setAllowFileAccessFromFileURLs(false)
        // 支持多窗口
        // 设置WebView是否支持多窗口，默认为false。
        webSetting.setSupportMultipleWindows(true)
        // 设置脚本是否允许自动打开弹窗，默认false，不允许
        webSetting.javaScriptCanOpenWindowsAutomatically = true
        // 让网页加载时适应 WebView 的宽度
        webSetting.loadWithOverviewMode = true
        //  允许网页使用宽视图窗口
        webSetting.useWideViewPort = true
    }

    private fun initWebChromeClient(webView: WebView) {
        val context: Context = webView.context
        webView.webChromeClient = object : WebChromeClient() {

            override fun getDefaultVideoPoster(): Bitmap? {
                return mDefaultBit
            }

            override fun onShowCustomView(p0: View?, callback: CustomViewCallback?) {
                KLog.i(TAG, "onShowCustomView() " +
                        "p0: $p0 ,callback: $callback ")
                try {
                    mWebViewChromeClientProxy?.onShowCustomViewProxy(p0, callback)
                    super.onShowCustomView(p0, callback)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onShowCustomView() XM_Exception: $e")
                }
            }


            override fun onHideCustomView() {
                KLog.i(TAG, "onHideCustomView() ")
                try {
                    mWebViewChromeClientProxy?.onHideCustomViewProxy()
                        ?: super.onHideCustomView()
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onHideCustomView() XM_Exception: $e")
                }
            }

            override fun onCreateWindow(
                webView: WebView?, isDialog: Boolean, isUserGesture: Boolean, message: Message?
            ): Boolean {
                val type = webView?.hitTestResult?.type
                KLog.i(TAG, "onCreateWindow() " +
                        "isDialog: $isDialog ,isUserGesture: $isUserGesture ,type: $type")
                return try {
                    mWebViewChromeClientProxy?.onCreateWindowProxy(webView, isDialog, isUserGesture, message)
                        ?: super.onCreateWindow(webView, isDialog, isUserGesture, message)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onCreateWindow() XM_Exception: $e")
                    false
                }
            }

            override fun onCloseWindow(webView: WebView?) {
                KLog.i(TAG, "onCloseWindow() ")
                try {
                    mWebViewChromeClientProxy?.onCloseWindowProxy(webView)
                        ?: super.onCloseWindow(webView)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onCloseWindow() XM_Exception: $e")
                }
            }

            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                KLog.i(TAG, "onProgressChanged() newProgress:$newProgress")
                try {
                    mWebViewChromeClientProxy?.onProgressChangedProxy(view, newProgress)
                        ?: super.onProgressChanged(view, newProgress)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onProgressChanged() XM_Exception: $e")
                }
            }

            override fun onJsAlert(webView: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
                KLog.i(TAG, "onJsAlert() url:$url message:$message")
                return try {
                    mWebViewChromeClientProxy?.onJsAlertProxy(webView, url, message, result)
                        ?: super.onJsAlert(webView, url, message, result)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onJsAlert() XM_Exception: $e")
                    false
                }
            }

            override fun onJsConfirm(webView: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
                KLog.i(TAG, "onJsConfirm() url:$url message:$message")
                return try {
                    mWebViewChromeClientProxy?.onJsConfirmProxy(webView, url, message, result)
                        ?: super.onJsConfirm(webView, url, message, result)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onJsConfirm() XM_Exception: $e")
                    false
                }
            }

            /**
             * 告诉客户端显示离开当前页面的导航提示框。
             * 如果返回true，由客户端处理确认提示框，调用合适的JsResult方法。
             * 如果返回false，则返回默认值true给javascript接受离开当前页面的导航。
             * 默认：false。JsResult设置false，当前页面取消导航提示，否则离开当前页面。
             * @param webView WebView
             * @param url String
             * @param message String
             * @param result JsResult
             * @return Boolean
             */
            override fun onJsBeforeUnload(
                webView: WebView?, url: String?, message: String?, result: JsResult?
            ): Boolean {
                KLog.i(TAG, "onJsBeforeUnload() url:$url message:$message")
                return try {
                    mWebViewChromeClientProxy?.onJsBeforeUnloadProxy(webView, url, message, result)
                        ?: super.onJsBeforeUnload(webView, url, message, result)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onJsBeforeUnload() XM_Exception: $e")
                    false
                }
            }

            override fun onJsPrompt(
                webView: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?
            ): Boolean {
                KLog.i(TAG, "onJsPrompt() url:$url message:$message")
                return try {
                    mWebViewChromeClientProxy?.onJsPromptProxy(webView, url, message, defaultValue, result)
                        ?: super.onJsPrompt(webView, url, message, defaultValue, result)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onJsPrompt() XM_Exception: $e")
                    false
                }
            }

            /**
             * Return value usage see FILE_CHOOSE_REQUEST in
             * [XmDemoActivity.onActivityResult]
             */
            override fun onShowFileChooser(
                webView: WebView?, filePathCallback: ValueCallback<Array<Uri?>>?, fileChooserParams: FileChooserParams?
            ): Boolean {
                KLog.i(TAG, "onShowFileChooser: " + fileChooserParams?.mode)
                return try {
                    mWebViewChromeClientProxy?.onShowFileChooserProxy(webView, filePathCallback, fileChooserParams)
                        ?: super.onShowFileChooser(webView, filePathCallback, fileChooserParams)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onShowFileChooser() XM_Exception: $e")
                    false
                }
            }

            override fun onReceivedTitle(webView: WebView?, title: String?) {
                super.onReceivedTitle(webView, title)
                KLog.i(TAG, "onReceivedTitle() title: $title")
                try {
                    mWebViewChromeClientProxy?.onReceivedTitleProxy(webView, title)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onReceivedTitle() XM_Exception: $e")
                }
            }

            override fun onGeolocationPermissionsShowPrompt(
                origin: String?, geolocationPermissionsCallback: GeolocationPermissions.Callback?
            ) {
                KLog.i(TAG, "onGeolocationPermissionsShowPrompt() origin: $origin")
                try {
                    mWebViewChromeClientProxy?.onGeolocationPermissionsShowPromptProxy(origin,
                        geolocationPermissionsCallback)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onGeolocationPermissionsShowPrompt() XM_Exception: $e")
                }
            }

            override fun onPermissionRequest(request: PermissionRequest?) {
                KLog.i(TAG, "onPermissionRequest() request: ${request?.resources}")
                try {
                    mWebViewChromeClientProxy?.onPermissionRequestProxy(request)
                        ?: super.onPermissionRequest(request)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onPermissionRequest() XM_Exception: $e")
                }
            }

            override fun onPermissionRequestCanceled(request: PermissionRequest?) {
                KLog.i(TAG, "onPermissionRequestCanceled() request:  ${request?.resources}")
                try {
                    mWebViewChromeClientProxy?.onPermissionRequestCanceledProxy(request)
                        ?: super.onPermissionRequestCanceled(request)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onPermissionRequestCanceled() XM_Exception: $e")
                }
            }
        }
    }

    private fun initWebViewClient(webView: WebView) {
        webView.webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                KLog.i(TAG, "onPageStarted() url:$url")
                try {
                    mWebViewClientProxy?.onPageStartedProxy(view, url, favicon)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onPageStarted() XM_Exception: $e")
                }
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                KLog.i(TAG, "onPageFinished() url:$url")
                try {
                    mWebViewClientProxy?.onPageFinishedProxy(view, url)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onPageFinished() XM_Exception: $e")
                }
            }


            override fun onReceivedError(webView: WebView?, errorCode: Int, description: String?, failingUrl: String?) {
                KLog.e(TAG, "onReceivedError() errorCode: $errorCode, description: $description, url: $failingUrl")

            }

            override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                KLog.e(TAG, "onReceivedSslError() error :${error}")
                try {
                    mWebViewClientProxy?.onReceivedSslErrorProxy(webView, handler, error)
                        ?:super.onReceivedSslError(view, handler, error)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onReceivedSslError() XM_Exception: $e")
                }
            }

            override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
                val forMainFrame = request?.isForMainFrame
                val url = request?.url
                val code = error?.errorCode
                val description = error?.description
                KLog.e(TAG, """onReceivedError() 
                |forMainFrame: $forMainFrame
                |url: $url
                |code: $code
                |description: $description""".trimMargin())
                try {
                    mWebViewClientProxy?.onReceivedErrorProxy(webView, request, error)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onReceivedError() XM_Exception: $e")
                }
            }

            override fun onReceivedHttpError(
                view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?
            ) {
                val forMainFrame = request?.isForMainFrame
                val url = request?.url
                val code = errorResponse?.statusCode
                KLog.e(TAG, """onReceivedHttpError() 
                |forMainFrame: $forMainFrame
                |url: $url
                |code: $code""".trimMargin())
                try {
                    mWebViewClientProxy?.onReceivedHttpErrorProxy(webView, request, errorResponse)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "onReceivedHttpError() XM_Exception: $e")
                }
            }

            override fun shouldOverrideUrlLoading(webView: WebView?, s: String?): Boolean {
                Log.w(TAG, "shouldOverrideUrlLoading() url: $s")
                return try {
                    mWebViewClientProxy?.shouldOverrideUrlLoadingProxy(webView, s) ?: super.shouldOverrideUrlLoading(
                        webView, s)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "shouldOverrideUrlLoading() XM_Exception: $e")
                    false
                }

            }

            override fun shouldOverrideUrlLoading(webView: WebView?, webResourceRequest: WebResourceRequest?): Boolean {
                Log.w(TAG, "shouldOverrideUrlLoading() requestUrl: ${webResourceRequest?.url}")
                return try {
                    mWebViewClientProxy?.shouldOverrideUrlLoadingProxy(webView, webResourceRequest)
                        ?: super.shouldOverrideUrlLoading(webView, webResourceRequest)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "shouldOverrideUrlLoading() XM_Exception: $e")
                    false
                }
            }

            override fun shouldInterceptRequest(
                webView: WebView?, webResourceRequest: WebResourceRequest?
            ): WebResourceResponse? {
                return try {
                    mWebViewClientProxy?.shouldInterceptRequestProxy(webView, webResourceRequest)
                        ?: super.shouldInterceptRequest(webView, webResourceRequest)
                } catch (e: Exception) {
                    e.printStackTrace()
                    KLog.e(TAG, "shouldInterceptRequest() XM_Exception: $e")
                    super.shouldInterceptRequest(webView, webResourceRequest)
                }
            }
        }
    }


    override fun destroy() {
        super.destroy()
        mWebViewChromeClientProxy = null
        mWebViewClientProxy = null
    }

    interface WebViewChromeClientProxy {

        fun onShowCustomViewProxy(
            view: View?,
            callback: WebChromeClient.CustomViewCallback?
        ) {

        }

        fun onHideCustomViewProxy() {

        }

        fun onCreateWindowProxy(
            webView: WebView?,
            isDialog: Boolean,
            isUserGesture: Boolean,
            message: Message?
        ): Boolean {
            return false
        }

        fun onCloseWindowProxy(webView: WebView?) {

        }

        fun onProgressChangedProxy(view: WebView?, newProgress: Int) {

        }

        fun onJsAlertProxy(webView: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
            return false
        }

        fun onJsConfirmProxy(webView: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
            return false
        }

        fun onJsBeforeUnloadProxy(
            webView: WebView?, url: String?, message: String?, result: JsResult?
        ): Boolean {
            return false
        }

        fun onJsPromptProxy(
            webView: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?
        ): Boolean {
            return false
        }

        fun onShowFileChooserProxy(
            webView: WebView?, filePathCallback: ValueCallback<Array<Uri?>>?,
            fileChooserParams: WebChromeClient.FileChooserParams?
        ): Boolean {
            return false
        }

        fun onReceivedTitleProxy(webView: WebView?, title: String?) {

        }

        fun onGeolocationPermissionsShowPromptProxy(
            origin: String?, geolocationPermissionsCallback: GeolocationPermissions.Callback?
        ) {

        }

        fun onPermissionRequestProxy(request: PermissionRequest?) {}

        fun onPermissionRequestCanceledProxy(request: PermissionRequest?) {}
    }

    interface WebViewClientProxy {
        fun onPageStartedProxy(view: WebView?, url: String?, favicon: Bitmap?) {
        }

        fun onPageFinishedProxy(view: WebView?, url: String?) {
        }

        fun onReceivedSslErrorProxy(view: WebView?, handler: SslErrorHandler?, error: SslError?) {

        }

        fun onReceivedErrorProxy(webView: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
        }

        fun onReceivedHttpErrorProxy(
            webView: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?
        ) {

        }

        fun shouldOverrideUrlLoadingProxy(webView: WebView?, s: String?): Boolean {
            return false
        }

        fun shouldOverrideUrlLoadingProxy(webView: WebView?, webResourceRequest: WebResourceRequest?): Boolean {
            return false
        }

        fun shouldInterceptRequestProxy(
            webView: WebView?, webResourceRequest: WebResourceRequest?
        ): WebResourceResponse? {
            return null
        }
    }
}